//
// Created by Alex on 17/3/13.
//


#include <string>
#include <netinet/in.h>
#include <vector>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <memory>

#include "libcr.h"
#include "libev.h"

struct Socket {
public:
  Socket(const std::string &conn);

  Socket(int fd);

  virtual ~Socket();

  bool Peek();

  bool Open();

  bool IsOpen();

  void Close();

  uint32_t Read(uint8_t *buf, uint32_t len);

  uint32_t Write(const uint8_t *buf, uint32_t len);

  void SetLinger(bool on, int linger);

  void SetNoDelay(bool noDelay);

  void SetRecvTimeout(int ms);

  void SetSendTimeout(int ms);

  bool OpenConnection();

  void SetInterrupt(std::shared_ptr<bool> interrupt);

  void SetIp(const std::string &ip);

  void SetPort(int port);

  void Ref();

  bool UnRef();

public:
  int m_socketFd;
  std::string m_peerIp;
  int m_peerPort;

  std::string m_localIp;
  int m_localPort;
  std::string m_protocol;

  int m_connectTimeout;
  int m_sendTimeout;
  int m_recvTimeout;
  bool m_isLinger;
  int m_lingerValue;
  bool m_noDelay;
  std::shared_ptr<bool> m_interrupt;
  std::atomic_int m_refCnt;
};

typedef void (*socket_listen_fun_t)(int fd);

struct ServerSocket {
  enum {
    DEFAULT_BACKLOG = 1024,
  };

  ServerSocket(const std::string &ip, int port);

  virtual ~ServerSocket();

  void SetSendTimeout(int sendTimeout);

  void SetRecvTimeout(int recvTimeout);

  void SetTcpSendBuffer(int kb);

  void SetTcpRecvBuffer(int kb);

  void SetListenCallback(const socket_listen_fun_t &listenCallback);

  void SetAcceptBackLog(int val);

  bool Listen();

  void Interrupt();

  void Close();

  Socket *Accept();

protected:
  int m_port;
  std::string m_ip;
  int m_socketFd;

  int m_acceptBacklog;
  int m_sendTimeout;
  int m_recvTimeout;

  int m_tcpSendBuffer;
  int m_tcpRecvBuffer;

  bool m_listening;
  std::shared_ptr<bool> m_interrupt;

  socket_listen_fun_t m_listenCallback;
};

